<?php
/**
 * 内部library
 * 
 * @author fzq
 * @date 2016-07-17
 * 
 * 使用方法 eg:
 * $dist = DistrictDicUtils::getInstance( $this->di );
 * $result = $dist->getDistrictsFromID( $areaId );
 * @return object( 省/市/区  和  当前所取的级别  )
 */
namespace libraries;
use enums\CachePrefixEnums;
use Phalcon\Db;
use enums\ServiceEnums;

if( !defined( 'APP_ROOT' ) ){ echo 'Direct Access Deny!'; return; }

class DistrictDicUtils implements \Phalcon\Di\InjectionAwareInterface
{
	static private $_instance = null;
	
// 	const DISTRICTS_NAME = 'h_district_name';
// 	const DISTRICTS_ID = 'h_district_id';
// 	const DISTRICT_CHILDREN = 'h_district_children';
// 	const DISTRICT_SELECTORS = 'h_district_selectors';

	const DISTRICT_TABLE_NAME = 'common_district_dic';
	
	private $_nredis = null;
	private $_di = null;
	/* (non-PHPdoc)
	 * @see \Phalcon\Di\InjectionAwareInterface::setDI()
	 */
	public function setDI(\Phalcon\DiInterface $dependencyInjector) {
		// TODO Auto-generated method stub
		$this->_di = $dependencyInjector;
	}

	/* (non-PHPdoc)
	 * @see \Phalcon\Di\InjectionAwareInterface::getDI()
	 */
	public function getDI() {
		// TODO Auto-generated method stub
		return $this->_di;
	}

	private function __construct( $di )
	{
       $this->_di = $di;
       
       $this->_nredis = $this->_di->get( ServiceEnums::SERVICE_NATIVE_REDIS );
	}
	
	static public function getInstance( $di )
	{
		if( is_null( self::$_instance ))
		{
			self::$_instance = new DistrictDicUtils( $di );
		}	
		
		return self::$_instance;
	} 
	
	/**
	 * 初始化缓存 系统中只需进行一次
	 */
	public function initCacheData()
	{
		if( $this->_nredis->hGet( CachePrefixEnums::DISTRICTS_ID, '1') )
		{//已初始化
			return;
		}
		
		$query = $this->_di['db']->query( 'select * from ' . self::DISTRICT_TABLE_NAME );
		$query->setFetchMode( Db::FETCH_ASSOC );

		while( $district = $query->fetch())
		{
			$this->_nredis->hSetNx( CachePrefixEnums::DISTRICTS_ID, $district['id'], json_encode( $district ) );
			$this->_nredis->hSetNx( CachePrefixEnums::DISTRICTS_NAME, $district['name'], json_encode( $district ) );
		}
				
	}
	
	/**
	 * 通过ID取区域的子区域
	 * @param number $id
	 * @return mixed|multitype:|NULL
	 */
	public function getChildrenFromID( int $id = 0 )
	{
		if( $id < 0 )
		{
			return false;
		}
		
FETCH_AGAIN://解决返回不同的问题
		if( $cacheContent = $this->_nredis->hGet( CachePrefixEnums::DISTRICT_CHILDREN, $id ) )
		{
			return json_decode( $cacheContent );
		}
		
		$query = $this->_di['db']->query( 'select * from ' . self::DISTRICT_TABLE_NAME . ' where upid=' . $id );

		if( $query->numRows() )
		{
			$query->setFetchMode( Db::FETCH_ASSOC );
			$arrRet = $query->fetchAll();
			$this->_nredis->hSet( CachePrefixEnums::DISTRICT_CHILDREN, $id, json_encode( $arrRet ) );
			
			goto FETCH_AGAIN;
			//return $arrRet;
		}
		
		return false;
	}
	
	public function getProvinces()
	{
		return $this->getChildrenFromID( 0 );
	}
	
	/**
	 * 通过区域名取子区域
	 * @param string $strName
	 * @return mixed|multitype:|NULL
	 */
	public function getChildrenFromName( string $strName = null )
	{
		$jsonDist = $this->getSingleDistFromName( $strName );

		if( !$jsonDist )
		{
			return false;	
		}
		
		if( $cacheContent = $this->_nredis->hGet( CachePrefixEnums::DISTRICT_CHILDREN, $jsonDist->id ) )
		{
			return json_decode( $cacheContent );
		}
		
// 		if( $jsonDist )
// 		{
// 			$arrRet = CommonDistrictDic::find( array( 'conditions' => 'upid=?1', 
// 					'bind' => array( 1 => $jsonDist->id ), 
// 			));
			
// 			if( $arrRet->count() )
// 			{
// 				$this->_nredis->hSet( CachePrefixEnums::DISTRICT_CHILDREN, $jsonDist->id, json_encode( $arrRet->toArray() ) );
// 				return $arrRet->toArray();
// 			}
// 		}
		
		return $this->getChildrenFromID( $jsonDist->id );
	}
	
	/**
	 * 通过ID取兄弟
	 */
	public function getSiblingsFromID( int $id )
	{
		if( $id <= 0 )
		{
			return false;
		}
		
		$jsonDist = $this->getSingleDistFromID( $id );
		
		if( !$jsonDist )
		{
			return false;
		}
		
		return $this->getChildrenFromID( $jsonDist->upid );
	}
	
	/**
	 * 通过名字取兄弟
	 */
	public function getSiblingsFromName( string $strName )
	{
		if( false === $strName || trim( $strName ) == '' )
		{
			return false;
		}
		
		$jsonDist = $this->getSingleDistFromName( $strName );
		
		if( !$jsonDist )
		{
			return false;
		}
		
		return $this->getChildrenFromID( $jsonDist->upid );
	}
	
	/**
	 * 取单个区域信息
	 * @param unknown $strName
	 * @return mixed|NULL
	 */
	public function getSingleDistFromName( string $strName )
	{
		$obj = $this->_nredis->hGet( CachePrefixEnums::DISTRICTS_NAME, $strName );
		
		if( $obj )
		{
			return json_decode( $obj );
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 取单个区域信息
	 * @param int $strID
	 * @return mixed|false
	 */
	public function getSingleDistFromID( int $iID )
	{
		if( $iID <= 0 )
		{
			return false;	
		}
		
		if( $obj = $this->_nredis->hGet( CachePrefixEnums::DISTRICTS_ID, $iID ) )
		{
			return json_decode( $obj );
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 取$id代表的区域和其所有祖先区域
	 * @param unknown $strName
	 * @return mixed
	 */
// 	public function getDistrictsFromName( $strName )
// 	{
// 		$strName = '"' . $strName . '"' ;
// 		$strDistsName = '"' . CachePrefixEnums::DISTRICTS_NAME . '"';
// 		$strDistrict = '"' . CachePrefixEnums::DISTRICTS_ID . '"';
		
// 		$script = <<<EOT
// 			local item = redis.call( 'hGet', $strDistsName, $strName );
// 			if item == nil then
// 				return nil;
// 			end
					
// 			local jsonItem = cjson.decode( item );
// 			local res = {};
// 			local level = 0;
// 			while true do
// 				level = level + 1;
// 				if( jsonItem['level'] == "1" ) then
// 					res['level' .. level] = jsonItem;
				
// 					res['level'] = level;
// 					return cjson.encode( res );	
// 				else
// 					res['level' .. level] = jsonItem;
// 					item = redis.call( 'hGet', 'h_district_id', jsonItem['upid'] );
// 					if item == nil then
// 						return nil;
// 					end
// 					jsonItem = cjson.decode( item );
// 				end
// 			end
// EOT;
		
		
// 		$obj = json_decode( $this->_nredis->eval( $script ));
		
// 		return $obj;
// 	}
	
	/**
	 * 使用方法
	 */
	public function test()
	{
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/海淀区/", var_export( $this->getChildrenFromID( 1 ), true ) ), true, 'getChildrenFromID(1)' );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/海淀区/", var_export( $this->getChildrenFromName( '北京市' ), true ) ), true, "getChildrenFromID('北京市')" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/广东省/", var_export( $this->getDistrictsFromID( 300 ), true ) ), true, "getDistrictsFromID( 300 )" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/广东省/", var_export( $this->getDistrictsFromName( '梅州市' ), true ) ), true, "getDistrictsFromName( '梅州市' )" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/合肥市/", var_export( $this->getSiblingsFromID( 200 ), true ) ), true, "getSiblingsFromID( 200 )" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/合肥市/", var_export( $this->getSiblingsFromName( '亳州市' ), true ) ), true, "getSiblingsFromName( '亳州市' )" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/亳州市/", var_export( $this->getSingleDistFromID( 200 ), true ) ), true, "getSingleDistFromID( 200 )" );
		echo $this->_di->get(ServiceEnums::SERVICE_UNIT_TEST)->run( preg_match( "/200/", var_export( $this->getSingleDistFromName( '亳州市' ), true ) ), true, "getSingleDistFromName( '亳州市' )" );
	}
	
	/**
	 * 
	 * @param number $id
	 */
// 	public function getDistrictFromIDWithAncestors( $id = 0 )
// 	{
		
// 	}
	
	/**
	 * 取$id代表的区域和其所有祖先区域
	 * @param number $id
	 * @return mixed
	 */
// 	public function getDistrictsFromID( $id = 0 )
// 	{
// 		$strDistrict = '"' . CachePrefixEnums::DISTRICTS_ID . '"';
		
// 		$script = <<<EOT
// 		local item = redis.call( 'hGet', $strDistrict, $id );
// 		if item == nil then
// 			return nil;
// 		end
// 		local jsonItem = cjson.decode( item );
// 		local res = {};
// 		local level = 0;
// 		while true do
// 				level = level + 1;
// 				if( jsonItem['level'] == "1" ) then
// 					res['level' .. level] = jsonItem;
		
// 					res['level'] = level;
// 					return cjson.encode( res );
// 				else
// 					res['level' .. level] = jsonItem;
// 					item = redis.call( 'hGet', $strDistrict, jsonItem['upid'] );
// 					if item == nil then 
// 						return nil;
// 					end
// 					jsonItem = cjson.decode( item );
// 				end
// 		end
// EOT;
// 		$obj = json_decode( $this->_nredis->eval( $script ));
		
// 		return $obj;
// 	}	
	
	public function getDistsWithSelsFromID( int $id = 0 )
	{
		if( $id > 0 )
		{		
			if( $cacheContent = $this->_nredis->hGet( CachePrefixEnums::DISTRICT_SELECTORS, $id ))
			{
				return json_decode( $cacheContent );
			}
			
			$objDistrict = $this->getSingleDistFromID( $id );
			
			if( !$objDistrict )
			{
				return false;
			}
			
			$arrRet = array();
			if( isset( $objDistrict->province_id ) )
			{
				$arrRet['provinces'] = $this->getProvinces();
			}
			
			if( isset( $objDistrict->city_id ) )
			{
				$arrRet['cities'] = $this->getSiblingsFromID( $objDistrict->city_id );
			}
			
			if( isset( $objDistrict->district_id ) )
			{
				$arrRet['districts'] = $this->getSiblingsFromID( $objDistrict->district_id );
			}
			
			$arrRet['name'] = $objDistrict->name;
			$arrRet['id'] = $objDistrict->id;
			
			$this->_nredis->hSet( CachePrefixEnums::DISTRICT_SELECTORS, $id, json_encode( $arrRet ));
			
			return $arrRet;
		}
		
		return false;
	}
	
	public function getDistsWithSelsFromName( string $strName )
	{
		if( false === $strName || trim( $strName ) == '' )
		{
			return false;
		}
		
		$objDist = $this->getSingleDistFromName( $strName );
		
		if( $objDist )
		{
			return $this->getDistsWithSelsFromID( $objDist->id );
		}
		
		return false;
	}
	
	
	/**
	 * @author( author='New' )
	 * @date( date = '2016年9月27日' )
	 * @comment( comment = '通过id查找到完整地址名' )
	 * @method( method = 'getWholeDistById' )
	 * @op( op = '' )
	 */
	public function getWholeDistById( int $id, string $address = null )
	{
		$district = '';
		if( $id > 0 )
		{
			$distObj = $this->getSingleDistFromID( $id );
			
			if( $distObj )
			{
				$district = $distObj->fullname;
			}
			
			if( $address )
			{
				$district .= $address;
			}
		}
		else
		{
			$district = $address ? : '';
		}
		
		return $district;
	}
}